﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Microsoft.Phone.Shell;
using System.Collections.ObjectModel;


namespace TodayHumor
{
    public class Board
    {
        string name; // 게시판 이름
        string id; // 게시판 구분 (bestofbest, windowsphone 등)
        int hit; // 사용자가 얼마나 게시글을 열었는지 횟수 : 게시판 정렬할 때 높은 순서대로 정렬함

        public Board(string name, string id, int hit)
        {
            this.name = name;
            this.id = id;
            this.hit = hit;
        }

        public string Name { get { return name; } }
        public string Id { get { return id; } }
        public int Hit { get { return hit; } set { hit = value; } }
    }

    public class ArticleList
    {
        Board board; // 게시글을 가지고 올 게시판
        int page; // 게시글을 가지고 올 페이지

        public ArticleList(Board board, int StartPage)
        {
            this.board = board;
            this.page = StartPage;
        }

        public async Task<List<Article>> LoadArticleList()
        {
            RaonWebClient WebClient = new RaonWebClient();

            string Uri = string.Format("http://m.todayhumor.co.kr/list.php?table={0}&page={1}", board.Id, page);
            string Result = await WebClient.DownloadStringTaskAsync(new Uri(Uri));

            // 다운로드받은 게시판의 게시글 정보를 파싱한 List를 반환한다.
            return ParseArticleList(Result);
        }

        List<Article> ParseArticleList(string TargetString)
        {
            List<Article> ArticleList = new List<Article>(); // 반환할 게시글 리스트

            // 정규 표현식
            Regex ArticleARegex = new Regex("<a href=\"view.php.*?\">(.|\n)*?</a>");
            Regex TitleRegex = new Regex("(?<=<h2 class=\"listSubject\" >)(.|\n)*?(?=</span>)");
            Regex HrefRegex = new Regex("(?<=<a href=\")(.|\n)*?(?=\")");
            Regex WriterRegex = new Regex("(?<=<span class=\"list_writer\".*?>)(.|\n)*?(?=</span>)");
            Regex LikeRegex = new Regex("(?<=<span class=\"list_okNokCount\">)(.|\n)*?(?=</span>)");
            Regex BoardRegex = new Regex("(?<=http://todayhumor.co.kr/board/images/).*?(?=\\')");
            Regex CommentRegex = new Regex("\\[[0-9]*?\\]");
            Regex MobileRegex = new Regex("<m>");

            // <a>로 싸여있는 게시글 정보의 MatchCollection을 가져와서
            MatchCollection ArticleAMatches = ArticleARegex.Matches(TargetString);

            foreach (Match ArticleAMatch in ArticleAMatches)
            {

                // 각각에 정보를 파싱한 뒤
                string Title = HttpUtility.HtmlDecode(TitleRegex.Match(ArticleAMatch.Value).Value);
                string Board = "/Images/BoardIcons/" + BoardRegex.Match(ArticleAMatch.Value).Value.Split('.')[0] + ".png";
                string Href = HrefRegex.Match(ArticleAMatch.Value).Value;
                string Writer = HttpUtility.HtmlDecode(WriterRegex.Match(ArticleAMatch.Value).Value.Split('<')[0]);
                string Like = LikeRegex.Match(ArticleAMatch.Value).Value;
                string Comments = CommentRegex.Match(ArticleAMatch.Value).Value;

                // 추가한다. 
                ArticleList.Add(new Article(Title, Board, Href, Writer, Like, Comments));
            }

            return ArticleList;
        }
    }

    public class BoardLoader
    {
        public ObservableCollection<Board> Boards = new ObservableCollection<Board>();

        string BoardSavePath = "/BoardList.txt";

        /// <summary>
        /// 게시판 목록을 로드합니다.
        /// </summary>
        public async void Load()
        {
            // Boards를 초기화하고
            Boards.Clear();

            // IsolatedStorage를 얻어와서
            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();

            // BoardList.txt가 있는지를 체크한 뒤
            if (storage.FileExists(BoardSavePath))
            {
                // 있으면 파싱한다. (게시판 이름 / 게시판 ID / 조회수 순으로 \t으로 구분됨)
                using (StreamReader BoardReader = new StreamReader(storage.OpenFile(BoardSavePath, FileMode.Open)))
                {
                    string ReadLine;
                    while ((ReadLine = BoardReader.ReadLine()) != null)
                    {
                        string[] ParsedString = ReadLine.Split('\t');

                        Boards.Add(new Board(ParsedString[0], ParsedString[1], Int32.Parse(ParsedString[2])));
                    }
                }
            }
            else
            {
                try
                {
                    await Refresh();
                }
                catch (WebException e)
                {
                    Debug.WriteLine(e.Response);
                }
            }
        }

        public void Save()
        {
            // hit 순으로 정렬하고
            Boards = new ObservableCollection<Board>(Boards.OrderByDescending(x => x.Hit));

            // IsolatedStorage를 얻어와서
            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();

            // BoardList.txt를 저장한다.
            using (StreamWriter BoardWriter = new StreamWriter(storage.OpenFile(BoardSavePath, FileMode.Create)))
            {
                foreach (Board board in Boards)
                {
                    BoardWriter.WriteLine(String.Format("{0}\t{1}\t{2}", board.Name, board.Id, board.Hit));
                }
            }
        }

        /// <summary>
        /// 게시판 목록을 초기화하고 다시 만듭니다.
        /// </summary>
        public async Task<bool> Refresh()
        {
            // WebClient를 이용하여 게시판 정보를 받아온 뒤
            RaonWebClient WebClient = new RaonWebClient();

            string Uri = "http://m.todayhumor.co.kr/";
            string Result = await WebClient.DownloadStringTaskAsync(new Uri(Uri));

            // 파싱한 후
            IEnumerable<Board> BoardList = ParseBoardList(Result);

            // IsolatedStorage를 얻어와서
            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();

            // BoardList.txt를 저장한다.
            using (StreamWriter BoardWriter = new StreamWriter(storage.OpenFile(BoardSavePath, FileMode.Create)))
            {
                foreach (Board board in BoardList)
                {
                    BoardWriter.WriteLine(String.Format("{0}\t{1}\t{2}", board.Name, board.Id, board.Hit));
                    Boards.Add(board);
                }
            }

            return true;
        }

        public ObservableCollection<Board> Search(string text)
        {
            ObservableCollection<Board> MatchBoards = new ObservableCollection<Board>();

            foreach (Board board in Boards)
            {
                if (board.Name.IndexOf(text) >= 0)
                {
                    MatchBoards.Add(board);
                }
            }

            return MatchBoards;
        }

        IEnumerable<Board> ParseBoardList(string result)
        {
            Regex BoardARegex = new Regex("<a href=\"list.php\\?table=.*?\">(.|\n)*?</a>");
            Regex HrefRegex = new Regex("(?<=<a href=\"list.php\\?table=)(.|\n)*?(?=\")");
            Regex TitleRegex = new Regex("(?<=</div>)(.|\n)*?(?=</div>)");

            IEnumerable<Board> BoardList = from BoardMatch in BoardARegex.Matches(result).OfType<Match>()
                                           let Name = Regex.Replace(TitleRegex.Match(BoardMatch.Value).Value, "<.*?>", "")
                                           let Id = HrefRegex.Match(BoardMatch.Value).Value
                                           select new Board(Name, Id, 0);

            return BoardList;
        }
    }
}